﻿//-----------------------------------------------------------------------
// <copyright>
// This file is subject to the terms and conditions of the Microsoft Public License (MS-PL).
// See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL for more details.
// </copyright>
//----------------------------------------------------------------------- 
using System;
using System.IO;
using System.Reflection;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Fulcrum.UnitTests
{
    public abstract class FulcrumGeneratedCodeTests
    {
        public FulcrumGeneratedCodeTests()
        {
            // nothing
        }

        public void ValidateGeneratedCode()
        {
            var path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

            var settings = FulcrumCodeGenerator.CreateSettings();
            settings.OutputDirectory = path;

            GenerationUnit genUnit = CreateGenerationUnit(path);

            genUnit.CreateDataContexts();

            Assert.AreNotEqual(0, genUnit.DataContexts.Count);

            RenameBaselineFiles(genUnit);

            FulcrumCodeGenerator.GenerateCode(settings, genUnit);

            ValidateGeneratedFiles(settings, genUnit);
        }

        protected abstract GenerationUnit CreateGenerationUnit(string path);

        private static void ValidateGeneratedFiles(FulcrumSettings settings, GenerationUnit wemGenUnit)
        {
            foreach (var dataContext in wemGenUnit.DataContexts)
            {
                string outputFileName = CreateFullOutputName(dataContext);
                string baselineFileName = CreateBaselineName(dataContext);

                var outputFile = Path.Combine(settings.OutputDirectory, outputFileName);
                var inputFile = Path.Combine(settings.OutputDirectory, baselineFileName);

                Console.WriteLine("copy \"{0}\"", outputFile);

                if (false == File.Exists(inputFile))
                {
                    throw new AssertFailedException(String.Format("The baseline file {0} doesn't exist", inputFile));
                }

                if (false == File.Exists(outputFile))
                {
                    throw new AssertFailedException(String.Format("The output file {0} doesn't exist", outputFile));
                }

                var areSame = DoesFileContentMatch(inputFile, outputFile);

                Console.WriteLine("windiff \"{0}\" \"{1}\"", inputFile, outputFile);
                Assert.IsTrue(areSame, "The file {0} is different", outputFile);
            }
        }

        private static void RenameBaselineFiles(GenerationUnit wemGenUnit)
        {
            foreach (var dataContext in wemGenUnit.DataContexts)
            {
                string outputFileName = CreateFullOutputName(dataContext);
                string baselineFileName = CreateBaselineName(dataContext);

                if (File.Exists(outputFileName))
                {
                    File.Move(outputFileName, baselineFileName);
                }
            }
        }

        private static string CreateBaselineName(GenerationDataContext dataContext)
        {
            string baselineFileName = CreateFullOutputName(dataContext) + ".baseline";
            return baselineFileName;
        }

        private static string CreateFullOutputName(GenerationDataContext dataContext)
        {
            string outputFileName = dataContext.OutputFileName + ".cs";
            return outputFileName;
        }

        public static bool DoesFileContentMatch(string fileOne, string fileTwo)
        {
            using (FileStream streamOne = new FileStream(fileOne, FileMode.Open, FileAccess.Read),
                              streamTwo = new FileStream(fileTwo, FileMode.Open, FileAccess.Read))
            {
                return DoStreamContentsMatch(streamOne, streamTwo);
            }
        }

        static bool DoStreamContentsMatch(Stream streamOne, Stream streamTwo)
        {
            if( streamOne.Length != streamTwo.Length)
            {
                return false;
            }

            using (StreamReader readerOne = new StreamReader(streamOne),
                               readerTwo = new StreamReader(streamTwo))
            {
                while (false == readerOne.EndOfStream)
                {
                    int one = readerOne.Read();
                    int two = readerTwo.Read();

                    if (one != two)
                    {
                        return false;
                    }
                }
            }

            return true;
        }
    }
}
